import fs from 'fs';
import JSZip from 'jszip';
import { DOMParser, XMLSerializer } from 'xmldom';

/**
 * 提取 docx 文件中的批注及其对应文字、段落词头和段落全文
 * @param {string} filePath - .docx 文件路径
 * @returns {Promise<Array<{id, author, date, text, target, title, paragraphText}>>}
 */
export async function extractCommentsWithTarget(filePath) {
  if (!fs.existsSync(filePath)) {
    throw new Error(`文件不存在: ${filePath}`);
  }

  const data = fs.readFileSync(filePath);
  const zip = await JSZip.loadAsync(data);

  // 1. 获取 comments.xml
  const commentsFile = zip.file('word/comments.xml');
  if (!commentsFile) {
    console.log('该文件中没有批注');
    return [];
  }
  const commentsXml = await commentsFile.async('string');
  const commentsDoc = new DOMParser().parseFromString(commentsXml, 'text/xml');
  const commentNodes = commentsDoc.getElementsByTagName('w:comment');

  // 2. 构建批注字典（来自 comments.xml）
  const commentsMap = {};
  for (let i = 0; i < commentNodes.length; i++) {
    const node = commentNodes[i];
    const id = node.getAttribute('w:id');
    const author = node.getAttribute('w:author') || '';
    const date = node.getAttribute('w:date') || '';
    const textNodes = node.getElementsByTagName('w:t');
    let text = '';
    for (let j = 0; j < textNodes.length; j++) {
      text += textNodes[j].textContent;
    }
    commentsMap[id] = { id, author, date, text: text.trim() };
  }

  // 3. 获取 document.xml（正文）
  const docFile = zip.file('word/document.xml');
  if (!docFile) {
    throw new Error('缺少 document.xml 文件');
  }

  const docXml = await docFile.async('string');
  const docDom = new DOMParser().parseFromString(docXml, 'text/xml');
  const body = docDom.getElementsByTagName('w:body')[0];

  // 4. 遍历正文节点（文档顺序），跟踪处于 commentRangeStart 与 commentRangeEnd 之间的文本
  const allNodes = body.getElementsByTagName('*');

  const activeComments = {}; // id -> true
  const commentTexts = {}; // id -> 被批注的原文片段
  const commentPara = {}; // id -> 所属段落节点

  let currentParagraph = null;

  // 辅助：获取某个段落的第一个 w:t（作为词头）和整段文本
  function getParagraphFirstText(pNode) {
    if (!pNode) return '';
    const tNodes = pNode.getElementsByTagName('w:t');
    for (let i = 0; i < tNodes.length; i++) {
      const txt = (tNodes[i].textContent || '').trim();
      if (txt) return txt;
    }
    return '';
  }

  function getParagraphFullText(pNode) {
    if (!pNode) return '';
    const tNodes = pNode.getElementsByTagName('w:t');
    let s = '';
    for (let i = 0; i < tNodes.length; i++) {
      s += tNodes[i].textContent || '';
    }
    return s.trim();
  }

  for (let i = 0; i < allNodes.length; i++) {
    const node = allNodes[i];
    const tagName = node.tagName;

    if (tagName === 'w:p') {
      currentParagraph = node;
    }

    if (tagName === 'w:commentRangeStart') {
      const id = node.getAttribute('w:id');
      if (!id) continue;
      activeComments[id] = true;
      commentTexts[id] = commentTexts[id] || '';
      // 首先把所属段落记下来（以 commentRangeStart 所在段落为准）
      if (!commentPara[id]) {
        commentPara[id] = currentParagraph;
      }
    } else if (tagName === 'w:commentRangeEnd') {
      const id = node.getAttribute('w:id');
      if (!id) continue;
      // 结束该批注的采集
      delete activeComments[id];
    } else if (tagName === 'w:t') {
      const txt = node.textContent || '';
      // 把当前文本分配给所有活跃的批注（支持嵌套/多个同时活跃）
      for (const cid in activeComments) {
        if (Object.prototype.hasOwnProperty.call(activeComments, cid)) {
          commentTexts[cid] = (commentTexts[cid] || '') + txt;
          // 如果还没有 paragraph 记下来，以当前段落为准
          if (!commentPara[cid]) commentPara[cid] = currentParagraph;
        }
      }
    }
  }

  // 5. 合并批注与对应文字、段落词头和整段释文
  const results = [];
  for (const id in commentsMap) {
    const targetRaw = (commentTexts[id] || '').trim();
    const paraNode = commentPara[id] || null;
    const title = getParagraphFirstText(paraNode);
    const paragraphText = getParagraphFullText(paraNode);

    results.push({
      ...commentsMap[id],
      target: targetRaw || '(未找到对应文字)',
      title: title || '(未找到词头)',
      paragraphText: paragraphText || '(未找到段落全文)'
    });
  }

  return results;
}

// 如果直接运行此脚本，做示例调用（仅在文件存在时执行）
if (process.argv[1] && process.argv[1].endsWith('app2.js')) {
  const demoPath = './demo.docx';
  if (!fs.existsSync(demoPath)) {
    console.log(`未找到 demo.docx，示例调用已跳过。将导出的函数用于实际 .docx 文件即可。`);
  } else {
    extractCommentsWithTarget(demoPath).then((comments) => {
      console.log('批注详情：');
      for (const c of comments) {
        console.log(`➡️ 批注ID ${c.id}`);
        console.log(`   作者：${c.author}`);
        console.log(`   时间：${c.date}`);
        console.log(`   被批注文字：${c.target}`);
        console.log(`   词头（title）：${c.title}`);
        console.log(`   段落全文：${c.paragraphText}`);
        console.log(`   批注内容：${c.text}`);
        console.log('---');
      }
    }).catch(err => {
      console.error('处理文件时报错：', err);
    });
  }
}
